/*------------------------------------------------------------------------------
$module:      EntryArray
$package:     CseApi
$purpose:     TEntryArray class definition
$author:      WAYNE WORK STDIO
$CreateAt:    08/07/04
$LastModify:
$license:     Mozilla Public License Version 1.1
------------------------------------------------------------------------------*/

#include "CseApi_.h"

#define CSE_DICT_MIN_SIZE          8

TCriticalSection CseEntryBuffLock;

STATIC PEntryPoint _EmptyDict = NULL;
const TEntryArray& CseEmptyDict = (TEntryArray&) _EmptyDict;

CseObj CseNull = NULL;

#ifndef CLOSE_REF_CHECK
  TInt32 TotalEntryArrayCount = 0;
#endif

class TEntryBuffLocker
{
public:
    TEntryBuffLocker(void)  { CseEntryBuffLock.enter(); }
    ~TEntryBuffLocker(void) { CseEntryBuffLock.leave(); }
};

STATIC PEntryPoint NewCseEntryBlock(int n)
{
    int iMask = CSE_DICT_MIN_SIZE;
    while (iMask < n) iMask = iMask * 2;

    int iNew = sizeof(CSE_DICT_EXT) + iMask * sizeof(TEntryPoint);
    CSE_DICT_EXT *pDictExt = (CSE_DICT_EXT *) new char[iNew];
    PEntryPoint ret = (PEntryPoint)((char *)pDictExt + sizeof(CSE_DICT_EXT));
    
    pDictExt->mask = iMask-1;
    pDictExt->FilledCount = 0;
    pDictExt->binded = dummy;
    pDictExt->count = 0;

    PEntryPoint pEntry = ret;
    for (int i = 0; i < iMask; i++,pEntry++)
    {
        pEntry->hash = 0;
        pEntry->key = NULL;
        pEntry->value = NULL;
    }
    
    return ret;
}

PEntryPoint Cse_BlockEntry(PEntryPoint pEntry, TUint32 mask, CseObj key, TUint32 hash)
{
    PEntryPoint freeslot;
    TUint32 i = hash & mask;
    PEntryPoint ret = pEntry + i;

    if (NULL == ret->key) return ret;

    if (ret->key == dummy)
        freeslot = ret;
    else
    {   // key must be unlinked
        if (ret->hash == hash && Cse_equal(ret->key,key))
            return ret;
        freeslot = NULL;
    }

    TUint32 perturb = hash;
    while (true)
    {
        i = (i << 2) + i + perturb + 1;  // more efficiency than: i * 5 + perturb + 1
        ret = pEntry + (i & mask);

        if (NULL == ret->key)
        {
            if (NULL != freeslot)
                ret = freeslot;
            return ret;
        }

        else if (ret->key == dummy)
        {
            if (NULL == freeslot)
                freeslot = ret;
        }

        else if (ret->hash == hash && Cse_equal(ret->key,key))
            return ret;

        perturb = perturb >> 5;  // more efficiency than: perturb / 32
    }
}

PEntryPoint Cse_BlockEntry(PEntryPoint pEntry, TUint32 mask, const TCharArray& sId, TUint32 hash)
{
    PEntryPoint freeslot;
    TUint32 i = hash & mask;
    PEntryPoint ret = pEntry + i;

    if (NULL == ret->key) return ret;

    if (ret->key == dummy)
        freeslot = ret;
    else
    {   // key must be unlinked
        if (ret->hash == hash && dtId == Cse_type(ret->key))
        {
            TCharArray *s = (TCharArray *)&ret->key->sValue;
            if (sId.compare(*s) == 0) return ret;
        }
        freeslot = NULL;
    }

    TUint32 perturb = hash;
    while (true)
    {
        i = (i << 2) + i + perturb + 1;  // more efficiency
        ret = pEntry + (i & mask);

        if (NULL == ret->key)
        {
            if (NULL != freeslot)
                ret = freeslot;
            return ret;
        }

        else if (ret->key == dummy)
        {
            if (NULL == freeslot)
                freeslot = ret;
        }

        else if (ret->hash == hash && dtId == Cse_type(ret->key))
        {
            TCharArray *s = (TCharArray *)&ret->key->sValue;
            if (sId.compare(*s) == 0) return ret;
        }
        
        perturb = perturb >> 5;  // more efficiency
    }
}

PEntryPoint Cse_BlockEntry(PEntryPoint pEntry, TUint32 mask, TInt iKey)
{
    TUint32 hash;
    if (sizeof(TInt) > 4)
    {   // 64 bits system
        TUint32 *p = (TUint32 *) &iKey;
        hash = *p ^ *(p+1);
    }
    else hash = iKey;

    PEntryPoint freeslot;
    TUint32 i = hash & mask;
    PEntryPoint ret = pEntry + i;

    if (NULL == ret->key) return ret;

    if (ret->key == dummy)
        freeslot = ret;
    else
    {   // key must be unlinked
        if (ret->hash == hash && dtInt == Cse_type(ret->key))
            if (ret->key->iValue == iKey) return ret;
        freeslot = NULL;
    }

    TUint32 perturb = hash;
    while (true)
    {
        i = (i << 2) + i + perturb + 1;  // more efficiency
        ret = pEntry + (i & mask);

        if (NULL == ret->key)
        {
            if (NULL != freeslot)
                ret = freeslot;
            return ret;
        }

        else if (ret->key == dummy)
        {
            if (NULL == freeslot)
                freeslot = ret;
        }

        else if (ret->hash == hash && dtId == Cse_type(ret->key))
        {
            if (ret->key->iValue == iKey)
                return ret;
        }

        perturb = perturb >> 5;  // more efficiency
    }
}

void Cse_SpecialFree(PEntryPoint pEntry, CseObj key, TUint32 hash)
{   // it is used for system ID-table management
    TEntryBuffLocker lock;

    CSE_DICT_EXT *pDictExt = (CSE_DICT_EXT *)((char *)pEntry - sizeof(CSE_DICT_EXT));
    
    pEntry = Cse_BlockEntry(pEntry,pDictExt->mask,key,hash);
    if (pEntry->value != NULL)
    {   // free value, but not free key
        CseObj v = pEntry->value;
        pEntry->key   = dummy;
        pEntry->value = NULL;

        pDictExt->count--;
        Cse_DecRef(v);
    }
}

// target entry buff must enough
void Cse_CopyEntry(PEntryPoint pTargEntry, PEntryPoint pSourEntry, TBool moved=false)
{
    CSE_DICT_EXT *pDictExtTarg = (CSE_DICT_EXT *)((char *)pTargEntry - sizeof(CSE_DICT_EXT));
    CSE_DICT_EXT *pDictExtSour = (CSE_DICT_EXT *)((char *)pSourEntry - sizeof(CSE_DICT_EXT));
    TUint32 mask = pDictExtTarg->mask;

    for (TUint32 i = 0; i <= pDictExtSour->mask; i++,pSourEntry++)
    {
    
        if (pSourEntry->value != NULL)
        {
            PEntryPoint pEntry = Cse_BlockEntry(pTargEntry,mask,pSourEntry->key,pSourEntry->hash);
            if (pEntry->value != NULL)
            {
                CseObj key   = pEntry->key;
                CseObj value = pEntry->value;
                pEntry->key   = NULL;           // avoid recursive free
                pEntry->value = NULL;           // avoid recursive free
                
                Cse_DecRef(key);
                Cse_DecRef(value);
            }
            else
            {
                if (pEntry->key == NULL && pDictExtTarg->FilledCount != mask)
                    pDictExtTarg->FilledCount++;
                pDictExtTarg->count++;
            }
            
            pEntry->hash  = pSourEntry->hash;
            if (moved)
            {
                pEntry->key   = pSourEntry->key;
                pEntry->value = pSourEntry->value;
                
                pSourEntry->key = dummy;
                pSourEntry->value = NULL;
                pDictExtSour->count--;
            }
            else
            {
                pEntry->key   = Cse_IncRefEx(pSourEntry->key);
                pEntry->value = Cse_IncRefEx(pSourEntry->value);
            }
        }
    }
}

STATIC CSE_DICT_EXT *TryCleanEntryBlock(PEntryPoint pEntry)
{
    CSE_DICT_EXT *pDictExt = (CSE_DICT_EXT *) ((char *)pEntry - sizeof(CSE_DICT_EXT));

    if (pDictExt->count > 0)
    {
        for (TUint32 i = 0; i <= pDictExt->mask; i++,pEntry++)
        {
            if (pEntry->value != NULL)
            {
                CseObj key   = pEntry->key;
                CseObj value = pEntry->value;
                pEntry->key   = NULL;          // avoid recursive free
                pEntry->value = NULL;          // avoid recursive free

                if (pDictExt->FilledCount != pDictExt->mask)
                    pDictExt->FilledCount--;
                pDictExt->count--;

                Cse_DecRef(key);
                Cse_DecRef(value);
            }
            else if (pEntry->key == dummy)
            {
                pEntry->key = NULL;
                if (pDictExt->FilledCount != pDictExt->mask)
                    pDictExt->FilledCount--;
            }
        }
    }
    // else, dict item has clear, no need check

    CseObj v = pDictExt->binded;
    pDictExt->binded = dummy;
    Cse_DecRef(v);

    return pDictExt;
}

STATIC void TryFreeEntryBlock(PEntryPoint pEntry)
{
    if (pEntry != NULL)
    {
        CSE_DICT_EXT *pDictExt = TryCleanEntryBlock(pEntry);
        delete []pDictExt;
    }
}

void TEntryArray::enlargeDict(int size)
{
    CSE_DICT_EXT *pDictExt = (CSE_DICT_EXT *)((char *)m_data - sizeof(CSE_DICT_EXT));
    if (size <= 0)
        size = pDictExt->mask + 2;
    else if ((TUint32) size <= pDictExt->mask + 1)
        return;  // space is enough, no need enlarge

    PEntryPoint pEntryNew = NewCseEntryBlock(size);
    Cse_CopyEntry(pEntryNew,m_data,true);

    TryFreeEntryBlock(m_data);
    m_data = pEntryNew;
}

TEntryArray::TEntryArray()
{
    m_data = NewCseEntryBlock(CSE_DICT_MIN_SIZE);
#ifndef CLOSE_REF_CHECK
    TotalEntryArrayCount++;
#endif
}

TEntryArray::TEntryArray(int MagicNum, TEntryArray& entry)
{
    CHECK_MSG(MagicNum == 20051206,_T("unauthorized call"));

    if (entry.m_data == _EmptyDict)
        m_data = NULL;
    else m_data = entry.transfer(NULL);
#ifndef CLOSE_REF_CHECK
    TotalEntryArrayCount++;
#endif
}

TEntryArray::TEntryArray(int n)
{
    m_data = NewCseEntryBlock(n);
#ifndef CLOSE_REF_CHECK
    TotalEntryArrayCount++;
#endif
}

TEntryArray::TEntryArray(const TEntryArray& entry)
{
    TEntryBuffLocker lock;
    
    if (entry.m_data == NULL)
        m_data = NULL;
    else
    {
        CSE_DICT_EXT *pDictExt = (CSE_DICT_EXT *)((char *)entry.m_data - sizeof(CSE_DICT_EXT));
        m_data = NewCseEntryBlock(pDictExt->mask + 1);
        Cse_CopyEntry(m_data,entry.m_data);
    }
#ifndef CLOSE_REF_CHECK
    TotalEntryArrayCount++;
#endif
}

TEntryArray::TEntryArray(PEntryPoint pSour)
{
    TEntryBuffLocker lock;
    m_data = NULL;
    joinEx(pSour);
#ifndef CLOSE_REF_CHECK
    TotalEntryArrayCount++;
#endif
}

TEntryArray::~TEntryArray()
{
    TEntryBuffLocker lock;
    TryFreeEntryBlock(m_data);
#ifndef CLOSE_REF_CHECK
    TotalEntryArrayCount--;
#endif
}

void TEntryArray::joinEx(PEntryPoint pSour)
{
    if (pSour == NULL) return;  // no need join
    
    CSE_DICT_EXT *pDictExtSour = (CSE_DICT_EXT *)((char *)pSour - sizeof(CSE_DICT_EXT));
    TUint32 iNew = pDictExtSour->count;
    TUint32 mask = 0;
    if (m_data != NULL)
    {
        CSE_DICT_EXT *pDictExtTarg = (CSE_DICT_EXT *)((char *)m_data - sizeof(CSE_DICT_EXT));
        iNew += pDictExtTarg->FilledCount;
        mask = pDictExtTarg->mask;
    }
    
    if ((iNew * 3) >= mask * 2)
    {   // if more than 2/3, should enlarge it to gain efficiency
        // iNew + iNew/2 = iNew * 3/2; iMask >= iNew * 3/2;
        // iNew <= iMask * 2/3;    => dict need not resize
        iNew += (iNew + 1) / 2;

        PEntryPoint pNewEntry = NewCseEntryBlock(iNew + 1);
        if (m_data != NULL)
            Cse_CopyEntry(pNewEntry,m_data);
        Cse_CopyEntry(pNewEntry,pSour);

        TryFreeEntryBlock(m_data);
        m_data = pNewEntry;
    }
    else Cse_CopyEntry(m_data,pSour);
}

TEntryArray& TEntryArray::join(const TEntryArray& entry)
{
    TEntryBuffLocker lock;
    joinEx(entry.m_data);
    return *this;
}

TEntryArray& TEntryArray::operator=(const TEntryArray& entry)
{
    TEntryBuffLocker lock;
    TryFreeEntryBlock(m_data);
    
    m_data = NULL;
    joinEx(entry.m_data);
    return *this;
}

void TEntryArray::operator+=(const TEntryArray& entry)
{
    join(entry);
}

TEntryArray TEntryArray::format(int ArgNum, ...)
{
    CHECK_MSG((ArgNum & 0x01) != 1, _T("argument number of TEntryArray::format() error"));

    va_list pArg;
    va_start(pArg, ArgNum);
    
    TEntryArray ret;
    for (int iCount = 1; iCount < ArgNum; iCount += 2)
    {
        TCseObj key = va_arg(pArg,CseObj);
        TCseObj value = va_arg(pArg,CseObj);
        ret.set(key,value);
    }
    va_end(pArg);

    return TEntryArray(CUT_FROM,ret);
}

PEntryPoint TEntryArray::addr() const
{
    return m_data;
}

int TEntryArray::len() const
{
    if (m_data == NULL)
        return 0;
    else return CSE_ARRAY_LEN(m_data);
}

TBool TEntryArray::isEmpty() const
{
    return len() <= 0;
}

TInt TEntryArray::compare(const TEntryArray& dOther) const
{
    return (TInt)m_data - (TInt)dOther.m_data;
}

PEntryPoint TEntryArray::idEntry(const TCharArray& sId, TUint32 hash) const
{
    CHECK_TRUE(m_data != NULL);
    TEntryBuffLocker lock;

    CSE_DICT_EXT *pDictExt = (CSE_DICT_EXT *)((char *)m_data - sizeof(CSE_DICT_EXT));
    return Cse_BlockEntry(m_data,pDictExt->mask,sId,hash);
}

PEntryPoint TEntryArray::intEntry(const TIntObj& iKey) const
{
    CHECK_TRUE(m_data != NULL);
    TEntryBuffLocker lock;

    CSE_DICT_EXT *pDictExt = (CSE_DICT_EXT *)((char *)m_data - sizeof(CSE_DICT_EXT));
    return Cse_BlockEntry(m_data,pDictExt->mask,iKey);
}

TCseObj TEntryArray::getById(const TCharArray& sId, TUint32 hash) const
{
    return idEntry(sId,hash)->value;
}

TCseObj TEntryArray::get(const TCseObj& key) const
{
    if (m_data == NULL) return dummy;

    CseObj key_ = *(CseObj *) &key;
    TStolenObj vTmp;
    if (Cse_type(key_) == dtInstance)
    {   // unlink and automatic transfer to normal key
        key_ = CseInstance_AsKey(key_);
        vTmp.bind(key_);
    }

    TEntryBuffLocker lock;
    CSE_DICT_EXT *pDictExt = (CSE_DICT_EXT *)((char *)m_data - sizeof(CSE_DICT_EXT));
    return Cse_BlockEntry(m_data,pDictExt->mask,key_,Cse_hash(key_))->value;
}

const TCseObj& TEntryArray::set(const TCseObj& key, const TCseObj& value)
{
    CseObj key_ = *(CseObj *)&key;
    TStolenObj vTmp;
    if (Cse_type(key_) == dtInstance)
    {   // unlink and automatic transfer to normal key
        key_ = CseInstance_AsKey(key_);
        vTmp.bind(key_);
    }

    TEntryBuffLocker lock;
    if (m_data == NULL)
        m_data = NewCseEntryBlock(CSE_DICT_MIN_SIZE);

    CseObj value_ = *(CseObj *)&value;
    if (value_ == dummy) value_ = NULL; // remove key:value

    setEx_(key_,value_,Cse_hash(key_));
    return value;
}

TCseObj TEntryArray::getEx(const TCseObj& key, const TCseObj& vDefault) const
{
    if (m_data == NULL) return vDefault;

    CseObj key_ = *(CseObj *)&key;
    TStolenObj vTmp;
    if (Cse_type(key_) == dtInstance)
    {   // unlink and automatic transfer to normal key
        key_ = CseInstance_AsKey(key_);
        vTmp.bind(key_);
    }

    TEntryBuffLocker lock;
    
    CSE_DICT_EXT *pDictExt = (CSE_DICT_EXT *)((char *)m_data - sizeof(CSE_DICT_EXT));
    PEntryPoint pEntry = Cse_BlockEntry(m_data,pDictExt->mask,key_,Cse_hash(key_));

    if (pEntry->value == NULL)
        return vDefault;
    else return pEntry->value;
}

void TEntryArray::setEx_(CseObj key, CseObj value, TUint32 hash, CseObj *OldValue)
{
    if (m_data == NULL) m_data = NewCseEntryBlock(CSE_DICT_MIN_SIZE);
    TEntryBuffLocker lock;

    CSE_DICT_EXT *pDictExt = (CSE_DICT_EXT *)((char *)m_data - sizeof(CSE_DICT_EXT));
    PEntryPoint pEntry = Cse_BlockEntry(m_data,pDictExt->mask,key,hash);
    if (NULL != OldValue)
        *OldValue = Cse_IncRefEx(pEntry->value);

    if (NULL != pEntry->value)
    {
        if (NULL == value)
        {
            CseObj v1 = pEntry->key;          // avoid recursive
            CseObj v2 = pEntry->value;
            pEntry->key   = dummy;
            pEntry->value = NULL;

            CSE_DICT_EXT *pDictExt = (CSE_DICT_EXT *)((char *)m_data - sizeof(CSE_DICT_EXT));
            pDictExt->count--;

            Cse_DecRef(v1);
            Cse_DecRef(v2);
        }
        else
        {
            CseObj v2 = pEntry->value;        // avoid recursive
            pEntry->value = Cse_IncRefEx(value);
            Cse_DecRef(v2);
        }
    }
    else    // pEntry->value == NULL
    {
        if (NULL != value)
        {
            CSE_DICT_EXT *pDictExt = (CSE_DICT_EXT *) ((char *)m_data - sizeof(CSE_DICT_EXT));

            // FilledCount == mask means fix size, disable to set, just temporary hold
            if (pDictExt->FilledCount == pDictExt->mask)
            {
                CseObj v2 = pDictExt->binded;
                pDictExt->binded = Cse_IncRefEx(value);
                Cse_DecRef(v2);
                return;
            }
            // else, the dict has empty space

            pDictExt->count++;
            if (NULL == pEntry->key && pDictExt->FilledCount != pDictExt->mask)
                pDictExt->FilledCount++;
            else ASSERT_TRUE(pEntry->key == dummy);

            pEntry->hash = hash;
            pEntry->key = Cse_IncRefEx(key);
            pEntry->value = Cse_IncRefEx(value);

            // if filled more than 2/3, should enlarge it to gain efficiency
            if ((pDictExt->FilledCount * 3) > (pDictExt->mask * 2))
                enlargeDict(0);
        }
    }
}

TCseObj TEntryArray::setEx(const TCseObj& key, const TCseObj& value)
{
    CseObj key_ = *(CseObj *)&key;
    TStolenObj vTmp;
    if (Cse_type(key_) == dtInstance)
    {   // unlink and automatic transfer to normal key
        key_ = CseInstance_AsKey(key_);
        vTmp.bind(key_);
    }

    TEntryBuffLocker lock;
    if (m_data == NULL)
        m_data = NewCseEntryBlock(CSE_DICT_MIN_SIZE);

    CseObj value_ = *(CseObj *)&value;
    if (value_ == dummy) value_ = NULL;  // remove key:value
    
    CseObj v = NULL;
    setEx_(key_,value_,Cse_hash(key_),&v);
    TCseObj ret(v); Cse_DecRef(v);
    
    return ret;
}

TBool TEntryArray::hasKey(const TCseObj& key) const
{
    if (m_data == NULL) return false;

    CseObj key_ = *(CseObj *)&key;
    TStolenObj vTmp;
    if (Cse_type(key_) == dtInstance)
    {   // unlink and automatic transfer to normal key
        key_ = CseInstance_AsKey(key_);
        vTmp.bind(key_);
    }

    TEntryBuffLocker lock;
    CSE_DICT_EXT *pDictExt = (CSE_DICT_EXT *)((char *)m_data - sizeof(CSE_DICT_EXT));
    return Cse_BlockEntry(m_data,pDictExt->mask,key_,Cse_hash(key_))->value != NULL;
}

PEntryPoint TEntryArray::transfer(PEntryPoint pOther)
{
    PEntryPoint ret = m_data;
    if (NULL == pOther)
        m_data = NULL; // this object invalid from then on, just wait to free
    else
    {
        CSE_DICT_EXT *pDictExt = (CSE_DICT_EXT *)((char *)pOther - sizeof(CSE_DICT_EXT));
        ASSERT_TRUE(pDictExt->mask >= pDictExt->FilledCount && pDictExt->FilledCount >= pDictExt->count);

        m_data = pOther;
    }
    return ret;
}

void TEntryArray::exchange(TEntryArray& other)
{
    TEntryBuffLocker lock;
    other.transfer(transfer(other.addr()));
}

void TEntryArray::clear()
{
    if (m_data == NULL) return;  // no need clear
    TEntryBuffLocker lock;

    CSE_DICT_EXT *pDictExt = (CSE_DICT_EXT *) ((char *)m_data - sizeof(CSE_DICT_EXT));
    if (pDictExt->FilledCount == pDictExt->mask)  // it is fix size
        TryCleanEntryBlock(m_data);  // clean but not realloc
    else
    {   // realloc buffer
        TryFreeEntryBlock(m_data);
        m_data = NewCseEntryBlock(CSE_DICT_MIN_SIZE);
    }
}

TCharArray TEntryArray::str() const
{
    TEntryBuffLocker lock;

    TCharArray ret(_T("{"));
    PEntryPoint pEntry = NULL;
    while (enumItem(pEntry))
    {
        TCharArray sTmp1,sTmp2;
        Cse_str(sTmp1,pEntry->key); // the key has unlinked
        Cse_str(sTmp2,Cse_unlink(pEntry->value));

        if (ret.len() > 1)
            ret += _T(',');
        ret.join(sTmp1).join(_T(':')).join(sTmp2);
    }
    ret += _T('}');

    return ret;
}

const TCseObj& TEntryArray::bind(const TCseObj& value) const
{
    CHECK_TRUE(m_data != NULL);
    TEntryBuffLocker lock;

    CSE_DICT_EXT *pDictExt = (CSE_DICT_EXT *)((char *)m_data - sizeof(CSE_DICT_EXT));
    CseObj v = pDictExt->binded;
    pDictExt->binded = Cse_IncRefEx(*(CseObj *)&value);
    Cse_DecRef(v);
    
    return value;
}

TCseObj TEntryArray::getBinding() const
{
    if (m_data == NULL) return dummy;

    TEntryBuffLocker lock;
    CSE_DICT_EXT *pDictExt = (CSE_DICT_EXT *)((char *)m_data - sizeof(CSE_DICT_EXT));
    return pDictExt->binded;
}

TBool TEntryArray::enumItem(PEntryPoint& pEntry, TCseObj *pKey, TCseObj *pValue) const
{
    if (m_data == NULL) return false;
    TEntryBuffLocker lock;

    if (pEntry == NULL)  // start enumlate
        pEntry = m_data;
    else pEntry++;

    // maybe the dict has resize
    if (pEntry < m_data) return false;

    CSE_DICT_EXT *pDictExt = (CSE_DICT_EXT *)((char *)m_data - sizeof(CSE_DICT_EXT));
    PEntryPoint LastAddr = m_data + pDictExt->mask;

    while (pEntry <= LastAddr)             // only loop within dict range
    {
        if (pEntry->value != NULL)
        {
            if (pKey != NULL)
                *pKey = pEntry->key;       // multi-thread safe
            if (pValue != NULL)
                *pValue = pEntry->value;   // multi-thread safe
            return true;
        }
        pEntry++;
    }
    return false;
}

int TEntryArray::fixSize(int iRsvd)
{
    TEntryBuffLocker lock;

    if (m_data == NULL)
        m_data = NewCseEntryBlock(CSE_DICT_MIN_SIZE);

    CSE_DICT_EXT *pDictExt = (CSE_DICT_EXT *) ((char *)m_data - sizeof(CSE_DICT_EXT));
    int iNewSize = pDictExt->count + iRsvd + 1;
    int iOldSize = pDictExt->mask + 1;
    
    if (iNewSize <= iOldSize)
    {
        pDictExt->FilledCount = pDictExt->mask;
        return iOldSize;   // fix space is enough
    }
    else
    {
        enlargeDict(iNewSize);
        
        pDictExt = (CSE_DICT_EXT *) ((char *)m_data - sizeof(CSE_DICT_EXT));
        pDictExt->FilledCount = pDictExt->mask;
        return pDictExt->mask + 1;
    }
}

TBool operator==(const TEntryArray& x,const TEntryArray& y)
{
    return x.compare(y) == 0;
}

TBool operator!=(const TEntryArray& x, const TEntryArray& y)
{
    return x.compare(y) != 0;
}
